package com.lr.frame.common.colorful.reflect;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.List;

import javassist.CannotCompileException;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtConstructor;
import javassist.CtField;
import javassist.CtMethod;
import javassist.CtNewConstructor;
import javassist.NotFoundException;

import com.lr.frame.common.colorful.aop.AspectTool;
import com.lr.frame.common.colorful.reflect.proxy.Station;

public class ClassTool {

	/**
	 * 获取非私有、非静态的函数(包含（非Object）父类的)
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Method> getDecararedMethods(Class<?> clazz,boolean getFinal) {
		List<Method> methods = new ArrayList<Method>();
		Class<?> nextClass = clazz;
		while (nextClass!=null&&nextClass != Object.class) {
			Method[] mary = nextClass.getDeclaredMethods();
			for (Method m : mary) {
				int modifiers = m.getModifiers();
				if (Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers))
					continue;
				if (Modifier.isFinal(modifiers)&&getFinal)
					continue;
				methods.add(m);
			}
			nextClass = nextClass.getSuperclass();
		}
		return methods;
	}
	/**
	 * 获取非私有、非静态的字段(包含（非Object）父类的)
	 * 
	 * @param clazz
	 * @return
	 */
	public static List<Field> getDecararedFields(Class<?> clazz,boolean getFinal) {
		List<Field> fields = new ArrayList<Field>();
		Class<?> nextClass = clazz;
		while (nextClass!=null&&nextClass != Object.class) {
			Field[] fary = nextClass.getDeclaredFields();
			for (Field f : fary) {
				int modifiers = f.getModifiers();
				if (Modifier.isStatic(modifiers))
					continue;
				if (Modifier.isFinal(modifiers)&&getFinal)
					continue;
				fields.add(f);
			}
			nextClass = nextClass.getSuperclass();
		}
		return fields;
	}
	

	
	/**
	 * 是否含有非私有、非静态的函数(不包含父类的)
	 * @param clazz
	 * @return
	 */
	public static boolean isExistSelfDeclaredMethod(Class<?> clazz){
		Method[] mary = clazz.getDeclaredMethods();
		for (Method m : mary) {
			int modifiers = m.getModifiers();
			if (Modifier.isPrivate(modifiers) || Modifier.isStatic(modifiers)){
				continue;
			}else{
				return true;
			}
		}
		return false;
	}

	/**
	 * 创建动态代理类
	 * @param proxyTarget
	 * @return
	 * @throws NotFoundException
	 * @throws CannotCompileException
	 */
	public static Class<?> createProxy(Class<?> proxyTarget) throws NotFoundException, CannotCompileException {
		return createProxyCt(proxyTarget).toClass();
	}
	public static CtClass createProxyCt(Class<?> proxyTarget) throws NotFoundException, CannotCompileException {
		ClassPool pool = ClassPool.getDefault();
		String canonicalName = proxyTarget.getCanonicalName();
		String simpleName = proxyTarget.getSimpleName();
		String proxyName = canonicalName.concat(";").replace(simpleName.concat(";"), simpleName.concat("$DynamicProxy"));
		// 创建代理类
		CtClass cc = pool.makeClass(proxyName);
		// 获取代理目标的接口
		Class<?>[] interfaces = proxyTarget.getInterfaces();
		CtClass item = null;
		/*
		 * 代理类实现代理目标的接口
		 */
		if (interfaces.length > 0) {
			for (int i = 0; i < interfaces.length; i++) {
				item = pool.get(interfaces[i].getCanonicalName());
				cc.addInterface(item);
			}
			if(ClassTool.isExistSelfDeclaredMethod(proxyTarget)){
				cc.setSuperclass(pool.get(canonicalName));
			}
		} else {
			cc.setSuperclass(pool.get(canonicalName));
		}
		// 给代理类创建一个代理目标的字段
		CtField cf = CtField.make("private ".concat(canonicalName).concat(" proxyTarget;"), cc);
		cc.addField(cf);
		// 给代理类创建构造函数
		CtClass stationClass = pool.get(canonicalName);
		CtClass[] arrays = new CtClass[] { stationClass };
		CtConstructor ccs = CtNewConstructor.make(arrays, null, CtNewConstructor.PASS_NONE, null, null, cc);
		ccs.setBody("this.proxyTarget=$1;");
		cc.addConstructor(ccs);
		
		CtMethod cthItem = null;
		List<Method> mthlist = getDecararedMethods(proxyTarget,true);
		for (Method mth : mthlist) {
			String mthStr = mth.toGenericString().replace(canonicalName + ".", "");
			String argsStr = "";
			if (!mthStr.endsWith("()")) {
				int rank = 1;
				while (mthStr.indexOf(",") > 0) {
					mthStr = mthStr.replaceFirst(",", " arg" + rank + "|");
					rank++;
					argsStr += "$" + rank + ",";
				}
				mthStr = mthStr.replace("|", ",").replace(")", " arg" + rank + ")");
				argsStr = argsStr.length() > 0 ? argsStr.substring(0, argsStr.length() - 1) : "$" + rank;
			}
			cthItem = CtMethod.make(mthStr + "{}", cc);
			String body = "{proxyTarget." + mth.getName() + "(" + argsStr + ");}";
			cthItem.setBody(body);
			cc.addMethod(cthItem);
		}
		return cc;
	}
	
	public static String getMethodStr(Method method) {
		return method.toGenericString();
	}

	public static void main(String[] args) throws Exception {
//		List<Method> ms=getDecararedMethods(TicketService.class); 
//		List<Method> msc=getDecararedMethods(Station.class);
//		System.out.println(ms);
//		System.out.println(msc);
		
//		Class<?> proc=ClassTool.createProxy(Station.class);
//		TicketService ticketService=(TicketService)proc.getConstructor(Station.class).newInstance(new Station());
//		ticketService.inquire();
//		ticketService.sellTicket("");
//		ticketService.withdraw();
//		((Station)ticketService).myService();
		
		
		Station station=AspectTool.createProxyObj(Station.class);
		station.inquire();
		station.sellTicket("");
		station.withdraw();
		station.myService();
	}
}
